package pocisk;

import java.awt.geom.Point2D;
import java.util.ArrayList;

/**
 *
 * @author kamil
 */
public class Simulation { //klasa do symulacji toru lotu pocisku

    public int method;
    public double gravity;
    public double velocity;
    public double mass; // niepotrzebne
    public int startx;
    public int starty;
    public int destinationx;
    public int destinationy;
    public ArrayList<Planet> universe;
    public double angle;
    public double dt;

    public Simulation() {
    }

    public Simulation(int method, double gravity, double velocity, ArrayList<Planet> universe, int startx, int starty, int destinationx, int destinationy, double angle, double dt) {
        this.method = method;
        this.gravity = gravity;
        this.velocity = velocity;
        this.universe = universe;
        this.startx = startx;
        this.starty = starty;
        this.destinationx = destinationx;
        this.destinationy = destinationy;
        this.angle = angle;
        this.dt = dt;
        //System.out.println("G=" + gravity + "\nV0=" + velocity + "\nstart=(" + startx + "," + starty + ")" + "\ndest=(" + destinationx + "," + destinationy + ")");
    }

    /**
     * Liczy przyśpieszenie w aktualnym punkcie
     *
     * @param cp   aktualny punkt
     * @return tablica [0] przyśpieszenieX, [1] przyśpieszenieY
     *
     */
    private double[] acceleration(Point2D.Double cp) {
        double gx = 0;
        double gy = 0;
        for (Planet planet : universe) {
            double r3 = Math.pow(Math.sqrt(Math.pow(planet.x - cp.x, 2) + Math.pow(planet.y - cp.y, 2)), 3);
            if (cp.x != planet.x) {
                gx += planet.mass * (-planet.x + cp.x) / r3;
            }
            if (cp.y != planet.y) {
                gy += planet.mass * (-planet.y + cp.y) / r3;
            }
        }
        gx *= -gravity;
        gy *= -gravity;

        //System.out.println("\t gravity"+gx + " "+gy);
        return new double[]{gx, gy};
    }

    /**
     * Metoda oblicza pierwszy krok rówania ruchu ze względu na brak dwóch pierwszych wartości
     *
     * @param points   tablica zawierająca dwa punkty: [0] punkt poprzedni, [1] punkt aktualny
     * @return tablica [0] punkt startowy, [1] pierwszy krok
     *
     */
    public Point2D.Double[] initialStep() {
        double[] acc = acceleration(new Point2D.Double(startx, starty));
        double gx = acc[0];
        double gy = acc[1];
        double xcp = startx + velocity * Math.cos(Math.toRadians(angle)) * dt + 0.5 * gx * dt * dt;
        double ycp = starty + velocity * Math.sin(Math.toRadians(angle)) * dt + 0.5 * gy * dt * dt;
        return new Point2D.Double[]{new Point2D.Double(startx, starty), new Point2D.Double(xcp, ycp)};
    }

    /**
     * Metoda oblicza kolejne położenie punktów na podstawie dwóch poprzednich,
     *
     * @param points   tablica zawierająca dwa punkty: [0] punkt poprzedni, [1] punkt aktualny
     * @return tablica [0] punkt akutalny, [1] punkt następny
     *
     */
    public Point2D.Double[] nextStep(Point2D.Double[] points) {
        double[] acc = acceleration(points[1]);
        double gx = acc[0];
        double gy = acc[1];
        Point2D.Double pp = points[0];
        Point2D.Double cp = points[1];
        double xnp = 2 * cp.x - pp.x + gx * dt * dt;
        double ynp = 2 * cp.y - pp.y + gy * dt * dt;
        //System.out.println("\txnp="+xnp+"\n\tynp="+ynp);
        return new Point2D.Double[]{new Point2D.Double(cp.x, cp.y), new Point2D.Double(xnp, ynp)};
    }
}
